#include "ChooseClient.h"
#include "ui_chooseclient.h"
#include "QDebug"
#include "QMessageBox"
#include "socket/csocketcommunication.h"
#include "socket/protocol/CarRequestPassenger.h"
#include "globalParameterForTaxi.h"
#include "assert.h"
#include "qbitmap.h"
#include <QTableWidgetSelectionRange>
#include "gpssimulator.h"
extern DRIVER_NAME g_driverInfo;
extern CHOSEN_CLIENT_INFO g_chosenClient;
extern GPSSimulator gpsSimulator;
int interface::CChooseClientInterface::m_sAvailableClientNum = 0;

interface::CChooseClientInterface::CChooseClientInterface(IInterface *parent)
    : IInterface(parent),
      m_pUi(new Ui::ChooseClient())
{
    m_pUi->setupUi(this);

    // setup the background
    this->UiSetting(m_pUi);

    m_pCarRequestPassenger = NULL;

    //load the map
    bMapLoad = false;
    mapProcessor = new MapProcessor(m_pUi->webWidget,this);
    mapProcessor->LoadMap();
    connect(mapProcessor,SIGNAL(finishLoading(bool)),SLOT(mapLoaded()));

    // connect between buttons and actions
    connect(m_pUi->btnCancel, SIGNAL(clicked()), this, SLOT(cancelChoose()) );
    connect(m_pUi->btnOK, SIGNAL(clicked()), this, SLOT(chooseTheClient()) );

    //connect the signals from socket
    connect(CSocketCommunication::GetInstance(), SIGNAL(canRead()), this, SLOT(readResult()) );
    connect(CSocketCommunication::GetInstance(), SIGNAL(socketError()), this, SLOT(socketError()) );

    m_chosenPassenger = -1;

    // TODO: let the customer wait
    // WaitForResultInterface();

    // format the table
    FormatTable(m_pUi->tableTaxiInfo);

    // now we start a timer, and every TIMEOUT ms will invoke the sendRequest slot.
    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(sendRequestByTime()));
    // start immediately
    m_pTimer->start(0);

    // TODO : for we will have to wait for the first driver to respond to your request,
    // so change the interface or just give out a message to notify customer to wait.
    // and we should set a timeout value to wait for timeout issue.
}

interface::CChooseClientInterface::~CChooseClientInterface()
{
    delete m_pUi;

    mapProcessor->CarChooseClientEnd();
    delete mapProcessor;

    m_pTimer->stop();
    delete m_pTimer;

    if (m_pCarRequestPassenger != NULL)
    {
        delete m_pCarRequestPassenger;
        m_pCarRequestPassenger = NULL;
    }

    for(int i = 0; i < m_vecItem.size(); i++)
    {
        for(int j = 0; j < m_vecItem[i].size(); j++)
        {
            delete m_vecItem[i][j];
        }
    }

    interface::CChooseClientInterface::clearClientNum();
}
void interface::CChooseClientInterface::mapLoaded()
{
    bMapLoad = true;
}
void interface::CChooseClientInterface::UiSetting(Ui::ChooseClient *ui)
{
    //setup the background
    IInterface::SetupBackground(QString("images\\background.jpg"));

    //setup the login button
    IInterface::SetupBtn(ui->btnOK, QString("images\\ChooseCar\\ok.png"));

    //setup the exit button
    IInterface::SetupBtn(ui->btnCancel, QString("images\\ChooseCar\\cancel.png"));
}

// button OK
// attention that in this interface, we do not need to send information to the server
void interface::CChooseClientInterface::chooseTheClient()
{
    // check whether the user has chosen a passenger
    if (m_chosenPassenger == -1)
    {
        QMessageBox::information(this, tr("warning in choose car"), \
                                 QString(tr("please choose a taxi")).append(tr("\nplease try again!")));
        return;
    }

    // user has chosen a taxi, and get the infomation now.
    g_chosenClient.client_id = m_mapRowToClientID.value(m_chosenPassenger);
    g_chosenClient.client_name = m_pUi->tableTaxiInfo->item(m_chosenPassenger, CLIENT_NAME)->text();
    g_chosenClient.mobile_phone = m_pUi->tableTaxiInfo->item(m_chosenPassenger, TEL)->text();
    g_chosenClient.arrivingTime = m_pUi->tableTaxiInfo->item(m_chosenPassenger, EXPECT_TIME)->text().toInt();
    g_chosenClient.startPos.lat = 1000000;
    g_chosenClient.startPos.lon = 1000000;
    g_chosenClient.endPos.lat = 1000000;
    g_chosenClient.endPos.lon = 1000000;

    // do not send request to server and change the interface right now
    emit changeInterfaces(interface::CHOOSE_CLIENT, interface::CONFIRM_CLIENT, (void*)&g_chosenClient);
}

// button CANCEL
void interface::CChooseClientInterface::cancelChoose()
{
    // just go back to the SERVICE CHOOSE interface
    emit changeInterfaces(interface::CHOOSE_CLIENT, interface::SERVICE_CHOOSE, NULL);
}

// when the communication between server and client is over,
// this function will be invoked
void interface::CChooseClientInterface::readResult()
{
    // receive the answers from server, we can now fill the table

    // first, we should add the corresponding relationship between row num and client_id
    m_mapRowToClientID.insert(getClientNum(), CSocketCommunication::GetInstance()->getResult(QString("client_id")));

    //********************************************************************
    // TODO : For ZJ. the new client data is sent by the server here. And map related
    // issues should be put here. All the necessary infomation can be fetched from
    // CSocketCommunication::GetInstance()->getResult(). The exact mapping definition can
    // be found in void CarRequestPassenger::formResult()
    //********************************************************************
    unsigned int startLat = CSocketCommunication::GetInstance()->getResult(QString("startGPS.lat")).toUInt();
    unsigned int startLon = CSocketCommunication::GetInstance()->getResult(QString("startGPS.lon")).toUInt();
    unsigned int endLat = CSocketCommunication::GetInstance()->getResult(QString("endGPS.lat")).toUInt();
    unsigned int endLon = CSocketCommunication::GetInstance()->getResult(QString("endGPS.lon")).toUInt();
    gpsSimulator.setStartEndPos(startLat,startLon,endLat,endLon);
    while(!bMapLoad);
    mapProcessor->CarChooseClientAddUser(startLat,startLon,endLat,endLon);

    // fill the first row of the table
    this->FillTable(m_pUi->tableTaxiInfo, CSocketCommunication::GetInstance()->getResult());
}

// an error occures when communicating with server
void interface::CChooseClientInterface::socketError()
{
    QMessageBox::information(this, tr("warning in choose car"), \
                             CSocketCommunication::GetInstance()->getErrorString().append(tr("\nplease try again!")));
}

// this function is to fill the table model, which will reflect the information recieved
// from the server. All the related data is stored in pClientInfoMap
void interface::CChooseClientInterface::FillTable(QTableWidget * pTableView, QMap<QString, QString> * pClientInfoMap)
{
    interface::CChooseClientInterface::increaseClientNum();
    pTableView->setRowCount(interface::CChooseClientInterface::getClientNum() );

    // now we can fill the data
    vector<QTableWidgetItem*> temp;

    QTableWidgetItem *UserIDItem = new QTableWidgetItem(pClientInfoMap->value(QString("client_id")));
    pTableView->setItem(interface::CChooseClientInterface::getClientNum() - 1, CLIENT_ID, UserIDItem);
    temp.push_back(UserIDItem);

    QTableWidgetItem *UserNameItem = new QTableWidgetItem(pClientInfoMap->value(QString("client_id")));
    pTableView->setItem(interface::CChooseClientInterface::getClientNum() - 1, CLIENT_NAME, UserNameItem);
    temp.push_back(UserNameItem);

    QTableWidgetItem *ArriveTimeItem = new QTableWidgetItem(pClientInfoMap->value(QString("timeout")));
    pTableView->setItem(interface::CChooseClientInterface::getClientNum() - 1, EXPECT_TIME, ArriveTimeItem);
    temp.push_back(ArriveTimeItem);

    QTableWidgetItem *PhoneItem = new QTableWidgetItem(pClientInfoMap->value(QString("honesty_degree")));
    pTableView->setItem(interface::CChooseClientInterface::getClientNum() - 1, TEL, PhoneItem);
    temp.push_back(PhoneItem);

    m_vecItem.push_back(temp);
}

void interface::CChooseClientInterface::SelectTableItem( int row, int column )
{
    // when a cell has been clicked, we should select the whole line
    QTableWidgetSelectionRange tableSelectionRange(row, 0,\
                                                   row, m_pUi->tableTaxiInfo->columnCount() - 1);
    m_pUi->tableTaxiInfo->setRangeSelected(tableSelectionRange, true);

    // choose this selected one as the primary choice of the user
    m_chosenPassenger = row;
}

void interface::CChooseClientInterface::FormatTable(QTableWidget * pTableView)
{
    // set the layout of the table
    QStringList stringList;
    stringList.append(QString(tr("Customer ID")));
    stringList.append(QString(tr("Customer Name")));
    stringList.append(QString(tr("Willing to wait(min)")));
    stringList.append(QString(tr("Tel")));

    pTableView->setColumnCount(COLUMNCOUNT);

    pTableView->setAutoFillBackground(false);

    //to change all the COLUMNCOUNT columns can fill the the whole view
    int eachCellWidth = (pTableView->width()) / COLUMNCOUNT;
    for(int i = 0; i < COLUMNCOUNT; i++)
    {
        pTableView->setColumnWidth(i, eachCellWidth);
    }

    // set the cell header name labels
    pTableView->setHorizontalHeaderLabels(stringList);

    // now we can connect the signal and the action
    // TODO: There exists a bug that when the user has clicked an item, the system
    // will raise the whole line, but when the user clicks blank spaces, the highlight line
    // will not be delighted. But the selection is till there!! What should we do??
    connect(pTableView, SIGNAL(cellClicked(int, int)), this, SLOT(SelectTableItem(int, int)));
}


void interface::CChooseClientInterface::sendRequestByTime()
{
    if (m_pCarRequestPassenger != NULL)
    {
        delete m_pCarRequestPassenger;
        m_pCarRequestPassenger = NULL;
    }

    m_pCarRequestPassenger = new protocal::CarRequestPassenger();
    memcpy(m_pCarRequestPassenger->carID, \
           g_driverInfo.car_id.toStdString().c_str(),
           g_driverInfo.car_id.toStdString().length() + 1);

    // send out the request for other available drivers
    CSocketCommunication::GetInstance()->sendRequest(protocal::CAR_REQUEST_PASSENGERS, \
                                                     (void*)m_pCarRequestPassenger, \
                                                     sizeof(protocal::CarRequestPassenger));
    m_pTimer->stop();
    // set the interval
    m_pTimer->setInterval(TIMEOUT);
}
